package com.weixin.engine.daily;

import java.util.LinkedList;

/**
 * editslog 双缓冲机制
 *
 * @author zhuoziyang
 * @date 2022/3/10 22:28
 */
public class EditsLog {

    private DoubleBuffer buffer = new DoubleBuffer();

    private long txid = 0L;

    private long currentSyncTxid = 0L;

    private volatile boolean isSyncing = false;

    public void write(String content) throws Exception {

        EditLog editLog = null;

        synchronized (this) {
            txid++;

            editLog = new EditLog();
            editLog.content = content;
            editLog.txid = txid;

            buffer.add(editLog);
        }

        syncLog(editLog.txid);

    }

    private void syncLog(long txid) throws Exception {

        synchronized (this) {

            if (currentSyncTxid >= txid) {
                return;
            }

            while (isSyncing) {
                wait();
            }

            if (currentSyncTxid >= txid) {
                return;
            }

            isSyncing = true;

            buffer.exchange();

            EditLog editLog = buffer.to.getLast();

            currentSyncTxid = editLog.txid;

        }

        buffer.flush();

        synchronized (this) {
            isSyncing = false;
            notifyAll();
        }

    }


    private class DoubleBuffer {

        /**
         * 往里面写的
         */
        private LinkedList<EditLog> from = new LinkedList<>();
        /**
         * 正在操作往磁盘写的，写完了就是空的
         */
        private LinkedList<EditLog> to = new LinkedList<>();

        public void add(EditLog editLog) {
            from.add(editLog);
        }

        /**
         * 能调用这个方法，那么说明此时 to 是空的
         */
        public void exchange() {
            LinkedList<EditLog> tmp = from;

            from = to;

            to = tmp;
        }

        public void flush() {
            for (EditLog editLog : to) {
                System.out.println(editLog.txid + ":" + editLog.content);
            }
        }

    }

    private class EditLog {

        private Long txid;

        private String content;

    }

}